package com.apes.framework.plugin.workflow;

import com.alibaba.fastjson.JSON;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.express.FuncAlias;
import com.apes.framework.plugin.outbox.OutboxSubscriber;
import com.apes.framework.plugin.outbox.OutboxSubscriberManager;
import com.apes.framework.plugin.websocket.WsMessage;
import com.apes.framework.plugin.websocket.WsPublisher;
import com.apes.framework.plugin.workflow.domain.ProcessInstanceExt;
import com.apes.framework.plugin.workflow.domain.ProcessInstanceExtService;
import com.apes.framework.plugin.workflow.parser.model.Node;
import com.apes.framework.rop.session.SimpleSession;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.hr.base.model.WorkPost;
import com.apes.hr.base.repository.WorkPostRepository;
import com.apes.scm.masterdata.frame.model.Branch;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.apes.scm.rbac.service.PostService;
import org.flowable.engine.ProcessEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能：工作流引擎Facets
 *
 * @author xul
 * @create 2017-11-29 14:11
 */
@Service("workflowEngineFacets")
public class WorkflowEngineFacets extends DomainService {

    @Qualifier("flowableEngine")
    @Autowired
    private WorkflowEngine engine;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    UserRepository userRepository;

    //流程管理：流程部署（）

    /**
     * 功能：流程部署
     */
    public void deploy() {

    }

    public void redeploy() {

    }

    @Listener(topic = "event:wf.startProcessInstanceById")
    public String startProcessInstanceById(SimpleRequest request) {
        Map data = request.getMap();
        String processDefinitionKey = (String) data.get("processDefinitionKey");
        Map variables = (Map) data.get("variables");
        return startProcessInstanceById(processDefinitionKey, variables);
    }

    /**
     * 功能：流程启动
     *
     * @param processDefinitionKey 工作流ID
     * @param variables            变量列表
     * @return 工作流实例编号
     */
    public String startProcessInstanceById(String processDefinitionKey, Map variables) {
        return engine.startProcessInstanceById(processDefinitionKey, variables);
    }


    /***
     * 查询客诉代办列表
     */

    public List<Map> getTasksForCustomComplain(SimpleRequest request) {
        // 获取当前登录人的userId
        User user = userRepository.findByOrigin((String) request.get("userId"));
        if (user == null) throw new RuntimeException("不存在相应的用户，原始用户编码：" + request.get("userId"));
        List<Map> tasks = engine.getTasks(user.getId().toString());
        List<Map> customComplainTasks = tasks.stream().filter(item -> {
            String title = item.get("title").toString();
            if (title.equals("客诉单")) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toCollection(ArrayList::new));
        if (customComplainTasks.size() == 0) return new ArrayList();
        return (List<Map>) customComplainTasks.get(0).get("list");
    }


    /**
     * 功能：查询待办列表
     */
    public List<Map> getTasks(SimpleRequest request) {
        String userId = getUserId(request);
        Map m = request.getMap();
        if (m.containsKey("page") && m.containsKey("size")) {
            int page = (int) m.get("page");
            int size = (int) m.get("size");
            return engine.getTasks(userId, page, size);
        } else {
            return engine.getTasks(userId);
        }
    }

    /**
     * 功能：查询待办列表
     */
    public Long getTaskCount(SimpleRequest request) {
        String userId = getUserId(request);
        return engine.getTaskCount(userId);
    }

    /**
     * 功能：查询待办列表
     */
    public Map getTaskByTaskId(SimpleRequest request) {
        String taskId = request.getJO().getString("taskId");
        return engine.getTaskByTaskId(taskId);
    }

    public String getUserId(SimpleRequest request) {
        String userId;
        try {
            userId = request.get("userId");
        } catch (Exception e) {
            SimpleSession session = getSession(request);
            if (session == null) throw new RuntimeException("请重新登陆！");
            userId = session.getUserId(); //任务执行人
        }
        if (Tools.isNull(userId)) throw new RuntimeException("用户ID不允许为空！");
        return userId;
    }

    /**
     * 功能：执行任务
     */
    public Map executeTask(SimpleRequest request) {
        Map variables = request.getMap();
        String taskId = request.get("wfTaskId");

        SimpleSession session = (SimpleSession) request.getRopRequestContext().getSession();
        if (session != null) {
            String taskExecutor = session.getUserId(); //任务执行人
            variables.put("taskExecutor", taskExecutor);
            PostService postService = SpringManager.getBean(PostService.class);
            Post post = postService.findOne(session.getPostId());

            Branch branch = post.getBranch();
            if (branch != null) {
                String processInitiatingDepartment = branch.getId(); //任务执行部门
                variables.put("taskExecutorDepartment", processInitiatingDepartment);
            }

            WorkPost workPost = post.getWorkPost();
            if (workPost != null) {
                String processInitiatingPost = workPost.getId(); //任务执行岗位
                variables.put("taskExecutorPost", processInitiatingPost);
            }
        }
        if (!variables.containsKey("taskExecutor") || Tools.isNull(variables.get("taskExecutor"))) {
            throw new RuntimeException("任务执行人不允许为空！");
        }
        engine.executeTask(taskId, variables);
        return new HashMap();
    }

    private ProcessInstanceExt getProcessInstanceExt(String businessType, String businessKey) {
        return processInstanceExtService.findByBusinessTypeAndBusinessKey(businessType, businessKey);
    }

    public ProcessInstanceExt findProcessInstanceExt(SimpleRequest request) {
        return getProcessInstanceExt(request.get("businessType"), request.get("businessKey"));
    }

    /**
     * 功能：挂起流程实例
     *
     * @param request
     * @return
     */
    public Map suspend(SimpleRequest request) {
        ProcessInstanceExt processInstanceExt = getProcessInstanceExt(request.get("innerBusinessType"), request.get("innerBusinessKey"));
        engine.suspendProcessInstanceById(processInstanceExt.getProcessInstanceId());
        return new HashMap();
    }

    @Autowired
    ProcessInstanceExtService processInstanceExtService;

    /**
     * 功能：激活流程实例
     *
     * @param request
     * @return
     */
    public Map activate(SimpleRequest request) {
        ProcessInstanceExt processInstanceExt = getProcessInstanceExt(request.get("innerBusinessType"), request.get("innerBusinessKey"));
        engine.activateProcessInstanceById(processInstanceExt.getProcessInstanceId());
        return new HashMap();
    }

    /***
     * 功能： 获取当前流程实例是否挂起
     */
    public boolean isProcessInstanceSuspend(SimpleRequest request) {
        ProcessInstanceExt processInstanceExt = getProcessInstanceExt(request.get("innerBusinessType"), request.get("innerBusinessKey"));

        if (processInstanceExt == null) return false;

        return processEngine.getTaskService().createTaskQuery().processInstanceId(processInstanceExt.getProcessInstanceId())
                .list().get(0).isSuspended();
    }

    @Autowired
    WsPublisher wsPublisher;

    @Autowired
    OutboxSubscriberManager outboxSubscriberManager;

    // 同步推送流程执行消息到客户端
    @Listener(topic = "event:ws.wf.task")
    public void onMessage(SimpleRequest request) {
        Map<String, String> message = request.getMap();
        WsMessage wsMessage = new WsMessage();
        String userId = message.get("userId");
        wsMessage.setTo(userId);
        Long taskCount = engine.getTaskCount(userId);
        if (message.get("action").equalsIgnoreCase("executeTask")) {
            taskCount = taskCount > 0 ? taskCount - 1 : taskCount;
        }
        wsMessage.setBody(JSON.toJSONString(mapper("topic", "ws.wf.count", "action", message.get("action"), "message", taskCount, "task", message.get("task"))));

        // SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wsMessage);
        wsPublisher.publish(wsMessage);
    }

    @Listener(topic = "outbox.subscriber.init")
    public OutboxSubscriber getOutboxSubscriber(SimpleRequest request) {
        OutboxSubscriber outboxSubscriber = new OutboxSubscriber();
        outboxSubscriber.setId("wf_message_publish");
        outboxSubscriber.setEventType("S");
        outboxSubscriber.setAggregateType(WsMessage.class.getName());
        outboxSubscriber.setName("待办消息推送");
        outboxSubscriber.setConsumer("wf.message.publish");
        outboxSubscriber.setReadonly(true);
        return outboxSubscriber;
    }

    public void publish(SimpleRequest request) {
        WsMessage wsMessage = request.getO(WsMessage.class);
        wsPublisher.publish(wsMessage);
    }

    @Listener(topic = "event:wf.checkFormApiExist")
    public boolean checkFormApiExist(SimpleRequest request) {
        Map data = request.getMap();
        String formId = (String) data.get("formId");
        String esbId = (String) data.get("esbId");
        return Node.exist(formId, esbId);
    }


    /**
     * 按岗位获取用户
     **/
    @FuncAlias(name = "按岗位获取用户")
    public List<String> getUsersForWorkPost(String deptIdOrName, String... workPostIdOrNames) {
        List<Dept> depts = invoke("cm.dept.queryDept", MapUtil.mapper("key", deptIdOrName));
        if (depts == null || depts.isEmpty()) return null;
        Dept dept = depts.stream().findFirst().orElse(null);
        if (dept == null) return null;
        List<String> users = new ArrayList<>();
        Arrays.stream(workPostIdOrNames).forEach(workPostIdOrName -> {
            WorkPost workPost = SpringManager.getBean(WorkPostRepository.class).find(workPostIdOrName);
            if (workPost == null) return;
            com.apes.framework.plugin.workflow.parser.model.User user = new com.apes.framework.plugin.workflow.parser.model.User();
            List<Map> rows = user.getUsersRecursiveByBranch(dept.getBranch(), workPost);
            if (rows == null || rows.isEmpty()) return;
            users.addAll(rows.stream().map(m -> String.valueOf(m.get("id"))).collect(Collectors.toList()));
        });
        return users;
    }
}
